"""Automatic camelCase ↔ snake_case conversion middleware.

⚠️ DEPRECATED: This middleware is currently DISABLED due to Content-Length errors.
⚠️ Status: Not in use (disabled in backend/app/core/app.py)
⚠️ Reason: Middleware modifies response headers causing runtime errors

This middleware ensures seamless communication between:
- Frontend (JavaScript/TypeScript) using camelCase
- Backend (Python) using snake_case

Without this middleware, developers would need to manually convert field names
in every API request and response.
"""

from __future__ import annotations

import json
from typing import Any

from fastapi import Request, Response
from humps import camelize, decamelize
from starlette.middleware.base import BaseHTTPMiddleware
from starlette.responses import StreamingResponse


class CaseConverterMiddleware(BaseHTTPMiddleware):
    """Convert request/response between camelCase and snake_case.

    Flow:
    1. Incoming Request (Frontend → Backend):
       - Frontend sends: {"fullName": "John", "emailAddress": "john@example.com"}
       - Middleware converts to: {"full_name": "John", "email_address": "john@example.com"}
       - Backend receives snake_case

    2. Outgoing Response (Backend → Frontend):
       - Backend returns: {"full_name": "John", "created_at": "2025-10-16"}
       - Middleware converts to: {"fullName": "John", "createdAt": "2025-10-16"}
       - Frontend receives camelCase

    Benefits:
    - No manual conversion needed in business logic
    - Consistent naming conventions on both sides
    - Works transparently with Pydantic models
    """

    async def dispatch(self, request: Request, call_next: Any) -> Response:
        """Process request and response through case conversion.

        Args:
            request: Incoming HTTP request
            call_next: Next middleware in chain

        Returns:
            Response with converted field names
        """
        # === Step 1: Convert Request (camelCase → snake_case) ===
        if request.method in ["POST", "PUT", "PATCH"]:
            # Only process JSON content
            content_type = request.headers.get("content-type", "")
            if "application/json" in content_type:
                try:
                    body = await request.body()
                    if body:
                        data = json.loads(body)
                        # Convert camelCase to snake_case
                        converted = decamelize(data)

                        # Create new request with converted body
                        async def receive() -> dict[str, Any]:
                            return {
                                "type": "http.request",
                                "body": json.dumps(converted).encode("utf-8"),
                            }

                        request._receive = receive  # type: ignore[attr-defined]
                except (json.JSONDecodeError, UnicodeDecodeError):
                    # Invalid JSON - let it pass through for FastAPI to handle
                    pass

        # === Step 2: Execute Request ===
        response = await call_next(request)

        # === Step 3: Convert Response (snake_case → camelCase) ===
        if isinstance(response, Response | StreamingResponse) and response.headers.get("content-type", "").startswith(
            "application/json"
        ):
            try:
                # Read response body
                body = b""
                async for chunk in response.body_iterator:
                    body += chunk

                if body:
                    data = json.loads(body.decode("utf-8"))
                    # Convert snake_case to camelCase
                    converted = camelize(data)

                    # Create new response with converted body
                    return Response(
                        content=json.dumps(converted, ensure_ascii=False),
                        status_code=response.status_code,
                        headers=dict(response.headers),
                        media_type="application/json",
                    )
            except (json.JSONDecodeError, UnicodeDecodeError):
                # Invalid JSON - return original response
                pass

        return response
